{"id":"cmw8rznu6000xnv2orqnt6be9","slug":"security level","judul":"security-level","deskripsi":null,"parentId":null,"urut":8,"kategori":"library","tag":"[]","status":"draft","versi":null,"konsep":"# Tingkat Keamanan Ekosistem Zomet\n\nAudit statis atas **29 repo** di `~/AppData/Local/hermes/repos`, 7 Nov 2026.\nMetode: pembacaan kode (rg/grep), bukan uji serang ke sistem berjalan.\n\n## Skor\n\n| Aspek | Nilai | Catatan |\n|---|---|---|\n| Isolasi tenant & hashing password | **B** | scoped query + bcrypt/argon2 di app utama |\n| Manajemen rahasia | **D** | token di URL git, keystore di repo, secret hardcoded |\n| Ketahanan brute force | **E** | tidak ada rate limit di satu pun API |\n| Header keamanan web | **E** | tanpa helmet/CSP/HSTS |\n| Penanganan gagal-konfigurasi | **D** | fail-open bila env kosong |\n| **Keseluruhan** | **C−** | fondasi ada, rahasia bocor |\n\n## Empat temuan kritis\n\n1. **Password Gitea di URL remote semua repo** — `http://<user>:<token>@103.93.129.94:3001/...`\n   tersimpan di `.git/config` tiap repo. Bocor satu = kendali seluruh 50 repo.\n2. **Keystore + password signing `pajak-kb-admin` ter-commit** — `keystore.properties`\n   memuat `storePassword`/`keyPassword` polos. Siapa pun bisa menerbitkan APK yang\n   diakui sebagai pembaruan resmi app itu.\n3. **Secret cadangan hardcoded dan masih diterima** — `z-ecosystem-admin-2026` di\n   `zone-repo/src/lib/secrets.ts`, `zxroom/lib/auth.ts`, `zx-carwash-api/src/routes/{admin,sso}.js`.\n4. **Fail-open** — `memberkit-api` membuka seluruh API bila `DEVICE_TOKEN` kosong;\n   `Z-Rooms/lib/jwt.ts` memakai `'fallback-secret'` bila `NEXTAUTH_SECRET` hilang.\n\n## Yang sudah benar\n\n- `bcrypt`/`argon2`: zx-carwash-api, acumedis-api, zone-repo, zpos\n- `crypto.timingSafeEqual` untuk membandingkan secret lintas-app\n- JWT SSO berumur **300 detik**\n- `addHook('preHandler', requireAuth)` global di zx-carwash-api\n- `.env` tidak pernah ter-commit (hanya `.env.example`)\n\n## Urutan kerja\n\n| # | Langkah | Dampak | Estimasi |\n|---|---|---|---|\n| 1 | Rotasi token Gitea, pindah ke credential helper | kendali repo | 30 mnt |\n| 2 | Keluarkan keystore dari git, ganti password | tanda tangan APK | 1 jam |\n| 3 | Hapus `OLD_SECRET` dari 4 berkas | admin lintas-app | 30 mnt |\n| 4 | Fail-closed bila env wajib kosong | akses tak berizin | 15 mnt |\n| 5 | Rate limit login 5/menit per IP+email | brute force | 1 jam |\n| 6 | Helmet + CSP + HSTS | clickjacking/downgrade | 1 jam |\n\nLangkah 1–4 adalah **rahasia yang sudah bocor**: memperbaiki kode tidak cukup,\nnilainya harus **diganti**.\n\n## Aturan yang dipegang saat mengerjakan\n\n- Rahasia asli **tidak** ditulis di halaman ini — blueprint ini tanpa autentikasi.\n- Setiap langkah diverifikasi dengan bukti (commit, deploy, tes), bukan klaim.\n- Tidak ada perubahan infra/DB tanpa persetujuan pemilik.\n","createdAt":"2026-11-09T04:43:07.752Z","updatedAt":"2026-11-09T04:44:33.045Z","bagian":[{"id":"cmw8s1u3r000znv2op3c2c6dx","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Ringkasan temuan","konten":"## Skor per proyek\n\n| Proyek | Jenis | Risiko utama |\n|---|---|---|\n| zone-repo (Z One) | Next.js + Prisma | `OLD_SECRET` hardcoded di `src/lib/secrets.ts` |\n| zxroom / Z-Rooms | Next.js | `OLD_SECRET` hardcoded + `fallback-secret` di `lib/jwt.ts` |\n| zx-carwash-api | Fastify | `OLD_SECRET` di `routes/admin.js` + `routes/sso.js` |\n| zx-carwash (app) | Android | outbox retry tanpa batas (terlindung `clientId`) |\n| memberkit-api | Node polos | **fail-open**: `DEVICE_TOKEN` kosong = API terbuka |\n| pajak-kb-api | Next.js | JWT tanpa rotasi kunci, cron pakai `JWT_SECRET` yang sama |\n| pajak-kb-admin | Android | **keystore + password di repo** |\n| acumedis-api | Fastify | hashing benar, tanpa rate limit |\n| ytvault-api | Python | token statis bersama, bukan per-pengguna |\n| zpos, zxgym, Zadv, zomet-main | Next.js | tanpa CSP/HSTS |\n\nSeluruh 29 repo memakai remote yang memuat token pribadi di URL.\n","media":"[]","urut":0,"createdAt":"2026-11-09T04:44:49.192Z","updatedAt":"2026-11-09T04:44:49.192Z"},{"id":"cmw8s1u5r0011nv2o5acd0sn0","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Rahasia yang sudah bocor","konten":"## Harus diganti, bukan ditambal\n\n### 1. Token Gitea di URL remote\n\n```\ngit remote get-url origin\n→ http://djvpri:<token>@103.93.129.94:3001/djvpri/<repo>.git\n```\n\nAda di `.git/config` **setiap** repo. Token ini bisa membuat, menghapus, dan\nmenimpa seluruh repo — termasuk memaksa auto-deploy Coolify berjalan.\n\n**Tindakan:** cabut token lama di Gitea, buat token baru, simpan lewat\ncredential helper (`git config --global credential.helper manager`), ubah remote\nmenjadi `http://103.93.129.94:3001/djvpri/<repo>.git` tanpa user:token.\n\n### 2. Keystore `pajak-kb-admin` di dalam git\n\n```\ngit show HEAD:keystore.properties\n  storePassword=<password polos>\n  keyAlias=pajakkbadmin\n  keyPassword=<password polos>\n```\n\n**Tindakan:** keluarkan `keystore.properties` + `app/keystore/release.jks` dari\nrepo (`git rm --cached`), tambahkan ke `.gitignore`, pindahkan JKS ke\n`C:/Users/Anjuv/keystores/`, ganti password keystore, lalu terbitkan APK baru\ndengan kunci itu. Catat: APK lama tetap sah sampai pengguna memasang versi baru.\n\n### 3. `z-ecosystem-admin-2026`\n\nDiterima sebagai secret cadangan di:\n\n```\nzone-repo/src/lib/secrets.ts:8\nzxroom/lib/auth.ts:36\nZ-Rooms/lib/auth.ts:36\nzx-carwash-api/src/routes/admin.js:29\nzx-carwash-api/src/routes/sso.js:36\n```\n\n**Tindakan:** hapus semua baris `OLD_SECRET`, sisakan satu sumber\n(`CROSS_APP_SECRET` dari env). Bila env kosong → **tolak start**, jangan diam.\n\n### 4. Fail-open\n\n```\nmemberkit-api/server.js:7    const TOKEN = process.env.DEVICE_TOKEN || ''\nmemberkit-api/server.js:93   if (TOKEN && ...) return 401     ← env kosong = lolos\nZ-Rooms/lib/jwt.ts:6         process.env.NEXTAUTH_SECRET || 'fallback-secret'\n```\n\n**Tindakan:** ganti menjadi gagal saat start bila env wajib tidak ada.\n","media":"[]","urut":1,"createdAt":"2026-11-09T04:44:49.263Z","updatedAt":"2026-11-09T04:44:49.263Z"},{"id":"cmw8s1u7y0013nv2o8io63ti6","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Celah tingkat tinggi","konten":"## Belum ada rate limit\n\n```\nzx-carwash-api   0 pembatas\nacumedis-api     0\nmemberkit-api    0\nytvault-api      0\npajak-kb-api     0\n```\n\nEndpoint login bisa dicoba ribuan kali tanpa hambatan; endpoint yang memanggil\nGemini/yt-dlp bisa dipakai menghabiskan kuota Anda.\n\n**Konsep:** pembatas per `IP + email`, 5 percobaan/menit, jeda bertambah setelah\n10 kegagalan. Simpan di memori proses (satu instance per app — cukup), tanpa Redis.\n\n## Belum ada header keamanan\n\n```\nhelmet / CSP / X-Frame-Options / HSTS → 0 hasil di 9 proyek web\n```\n\n**Konsep:** satu middleware bersama. `X-Frame-Options: DENY` untuk halaman\naplikasi, `frame-ancestors 'none'`, `Strict-Transport-Security: max-age=31536000`,\ndan CSP longgar dulu (laporkan pelanggaran, baru perketat) agar tidak mematahkan\nhalaman yang ada.\n","media":"[]","urut":2,"createdAt":"2026-11-09T04:44:49.342Z","updatedAt":"2026-11-09T04:44:49.342Z"},{"id":"cmw8s1ua50015nv2o716bkqz5","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Risiko tingkat sedang","konten":"## Token YTVault dipakai bersama\n\n`ytvault-api` memakai satu `API_TOKEN` statis untuk semua pemasangan. Bocor dari\nsatu APK = siapa pun bisa memakai server Anda untuk mengunduh.\n\n**Konsep:** token per pemasangan (dibuat saat pertama kali app dijalankan),\ndisimpan server, bisa dicabut satu per satu di Setelan.\n\n## Isolasi tenant bergantung disiplin query\n\nSemua `findMany` di zx-carwash-api sudah ber-`tenantId`, tetapi **tidak ada\nconstraint di DB** yang memaksa. Satu rute baru yang lupa menyaring = data\nlintas tenant terbaca.\n\n**Konsep:** bungkus akses Prisma dalam helper `db.tenant(tenantId)` yang selalu\nmenyisipkan filter — bukan mengandalkan ingatan penulis kode.\n\n## Cron memakai kunci yang sama dengan sesi\n\n`pajak-kb-api/src/app/api/cron/expire/route.ts` memakai `JWT_SECRET` sebagai\nheader cron. Bocor satu = bisa memicu job apa pun.\n\n**Konsep:** kunci terpisah `CRON_SECRET`, hanya untuk cron, tanpa hak membuat sesi.\n","media":"[]","urut":3,"createdAt":"2026-11-09T04:44:49.421Z","updatedAt":"2026-11-09T04:44:49.421Z"},{"id":"cmw8s1ucw0017nv2o69ny8my8","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Rencana kerja bertahap","konten":"## Tahap 0 — persiapan (10 menit)\n\n- Catat semua remote repo sebelum diubah (`git remote -v > remote-lama.txt`).\n- Pastikan punya salinan `keystore` dan password baru di tempat aman.\n\n## Tahap 1 — rahasia yang bocor\n\n| # | Langkah | Verifikasi |\n|---|---|---|\n| 1 | Cabut token Gitea lama, buat baru | token lama → 401 |\n| 2 | Ubah remote tanpa token + credential helper | `git fetch` jalan tanpa user:token di URL |\n| 3 | Keluarkan JKS + `keystore.properties` dari git | `git ls-files` tidak memuatnya |\n| 4 | Ganti password keystore, terbitkan APK baru | `apksigner verify` + pasang di HP |\n| 5 | Hapus `OLD_SECRET` di 5 berkas, wajibkan env | app menolak start bila env kosong |\n| 6 | Fail-closed memberkit-api & Z-Rooms | API menolak saat env kosong |\n\n## Tahap 2 — pengerasan\n\n| # | Langkah | Verifikasi |\n|---|---|---|\n| 7 | Rate limit 5/menit per IP+email di 5 API | percobaan ke-6 → 429 |\n| 8 | Helmet + CSP lapor + HSTS di 9 app web | header terlihat di `curl -I` |\n| 9 | Token cron terpisah (`CRON_SECRET`) | header lama → 401 |\n| 10 | Token YTVault per pemasangan | satu token dicabut, sisanya jalan |\n\n## Tahap 3 — struktural (opsional)\n\n- Helper `db.tenant(tenantId)` di zx-carwash-api, acumedis-api, memberkit-api.\n- Uji regresi: satu tes per app yang memastikan permintaan tanpa token → 401,\n  dan permintaan tenant A tidak melihat data tenant B.\n\n## Aturan pelaksanaan\n\n1. Satu langkah per commit, satu verifikasi nyata per langkah.\n2. Tidak ada perubahan DB/infra tanpa persetujuan.\n3. Setiap langkah dicatat hasilnya di halaman ini.\n","media":"[]","urut":4,"createdAt":"2026-11-09T04:44:49.521Z","updatedAt":"2026-11-09T04:44:49.521Z"},{"id":"cmw8s1uex0019nv2o5vjwabod","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Catatan metode","konten":"## Yang diperiksa\n\n- `rg` untuk pola rahasia, hashing, rate limit, header, timing-safe compare.\n- `git ls-files` untuk mencari berkas kredensial yang ter-commit.\n- `git remote get-url` untuk melihat token di URL.\n- Pembacaan `preHandler`/`middleware` untuk memastikan auth global.\n\n## Yang **tidak** diperiksa\n\n- Uji serang ke sistem berjalan (tidak dilakukan — hanya analisis statis).\n- Konfigurasi Coolify, firewall VPS, dan sertifikat TLS.\n- Dependensi usang (perlu `npm audit` terpisah per repo).\n- Keamanan di sisi perangkat (root, APK sideload, penyimpanan lokal terenkripsi).\n\nSkor di halaman ini adalah penilaian atas **kode yang terbaca**, bukan jaminan\nbahwa sistem aman. Bagian yang tidak diperiksa di atas dapat mengubah gambaran.\n","media":"[]","urut":5,"createdAt":"2026-11-09T04:44:49.593Z","updatedAt":"2026-11-09T04:44:49.593Z"},{"id":"cmw8sb9c0001bnv2olpmkmii9","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Temuan lanjutan: server & dependensi","konten":"## Ditemukan pada pemeriksaan lanjutan (7 Nov, malam)\n\nSaya periksa hal-hal yang belum masuk audit pertama: port server, dependensi,\nSSRF, dan isolasi runtime. Hasilnya menambah **satu temuan kritis baru** dan\nsatu masalah serius yang tidak terlihat dari kode.\n\n### K1 — SELURUH PORT TERBUKA KE INTERNET, TANPA FIREWALL\n\n```\nss -tlnp di VPS\n  0.0.0.0:22     sshd\n  0.0.0.0:5432   docker-proxy  → container nginx zpos\n  0.0.0.0:3001   gitea\n  0.0.0.0:8000   coolify\n\nufw status          → inactive\niptables -S INPUT   → -P INPUT ACCEPT\n```\n\n**Artinya:** Coolify (panel yang bisa men-deploy apa pun), Gitea (sumber semua\nkode), dan SSH dapat dijangkau dari internet mana pun. Tidak ada satu pun aturan\nfirewall. Satu password lemah = seluruh ekosistem jatuh.\n\nPort **5432** terbuka karena container proxy milik app `zpos` memetakan\n`5432 -> 0.0.0.0:5432`. Itu pemetaan yang tidak perlu: proxy Coolify seharusnya\nhanya mendengarkan 80/443.\n\n**Konsep perbaikan:**\n\n| # | Langkah | Verifikasi |\n|---|---|---|\n| 1 | `ufw default deny incoming` + `allow 22,80,443` | `nmap` dari luar: hanya 3 port |\n| 2 | Batasi panel: Coolify 8000 & Gitea 3001 hanya via SSH tunnel atau IP kantor | `curl` dari luar → connection refused |\n| 3 | Hapus pemetaan `5432:5432` pada container proxy zpos | `ss -tlnp` tidak memuat 5432 |\n| 4 | SSH: matikan login password, wajib kunci | `ssh -o PreferredAuthentications=password` → ditolak |\n| 5 | fail2ban untuk SSH & Gitea | 5 gagal login → IP diblokir 1 jam |\n\nIni **tidak** memerlukan perubahan kode aplikasi sama sekali, dan dampaknya\npaling besar dibanding semua langkah lain.\n\n### K2 — Dependensi: 3 kerentanan kritis `next` + RCE di `next/og`\n\nHasil `npm audit --omit=dev` per app:\n\n| App | Kritis | High | Yang paling berbahaya |\n|---|---|---|---|\n| zone-repo | 3 | 5 | `next` middleware bypass, `@auth/core` normalisasi email |\n| zxroom / Z-Rooms | 1 | 4 | **`next` RCE di `next/og` ImageResponse** |\n| zxgym | 2 | 3 | `@auth/core`, `next` DoS |\n| zpos | 1 | 6 | `next` middleware bypass, `xlsx` prototype pollution |\n| Zadv | 1 | 4 | `next` DoS |\n| zomet-main | 1 | 5 | `next` DoS, `js-yaml` ReDoS |\n| pajak-kb-api | 0 | 0 | 6 moderate |\n| acumedis-api | 0 | 2 | `fastify`/`find-my-way` DDoS |\n| zx-carwash-api | 0 | 2 | `find-my-way` DDoS |\n\n`s-next` versi lama dipakai di `zomet-main` (`^14.2.0`), `zxgym` (`14.2.35`).\nDua app memakai `next@16.3.4` yang masih kena RCE `next/og`.\n\n**Konsep:** naikkan satu per satu dengan urutan risiko: `zxroom`, `Z-Rooms`,\n`zone-repo` (paling terekspos publik) lebih dulu. `npm audit fix` biasa dulu;\n`--force` hanya bila mayor, dan itu perlu uji halaman.\n\n### K3 — SSRF & pemakaian kuota di ytvault-api\n\n```python\ndef info(request, url: str):\n    auth(request)\n    y.extract_info(url, download=False)     # url dari klien, tanpa batas\n```\n\n`url` diterima apa adanya. yt-dlp mengikuti URL itu; tanpa allowlist, server Anda\nbisa dipakai mengambil alamat internal (`http://127.0.0.1`, `10.0.1.x`, metadata\ncloud) atau menghabiskan kuota/disk.\n\n**Konsep:** tolak host selain `youtube.com`/`youtu.be`/`music.youtube.com`,\nbatasi panjang URL, batasi 1 job per menit, dan bersihkan berkas job lama\notomatis.\n\n### K4 — Token Gitea masih di dalam riwayat commit?\n\nPerlu diperiksa — token di URL remote tidak masuk commit, tetapi `keystore.properties`\n**sudah** masuk. Mengeluarkannya dari HEAD tidak menghapusnya dari riwayat;\nsiapa pun yang punya klon lama masih bisa membacanya.\n\n**Konsep:** anggap password keystore itu **sudah bocor** dan ganti. Untuk riwayat,\ncukup: repo Gitea bersifat privat dan hanya Anda yang punya akses, jadi\npenulisan ulang riwayat (`filter-repo`) tidak wajib — tetapi password tetap\nharus diganti.\n\n### Ringkasan prioritas baru\n\n```\nP0  Firewall VPS + tutup 5432 + batasi panel    (tanpa ubah kode, 30 menit)\nP1  Rotasi token Gitea & password keystore\nP2  Hapus OLD_SECRET + fail-closed\nP3  Rate limit + header keamanan\nP4  Naikkan dependensi (next, @auth/core, fastify)\nP5  SSRF allowlist + token per pemasangan\n```\n","media":"[]","urut":6,"createdAt":"2026-11-09T04:52:08.832Z","updatedAt":"2026-11-09T04:52:08.832Z"},{"id":"cmwab5ati001dnv2oiy44ot3s","blueprintId":"cmw8rznu6000xnv2orqnt6be9","judul":"Backup & pemulihan (koreksi temuan)","konten":"## Temuan: tidak ada backup sama sekali → dikoreksi\n\nSaya awalnya melaporkan \"backup tidak ada\". **Itu salah.** Saya hanya membaca\n`crontab root` dan melewatkan jadwal backup yang hidup di dalam Coolify.\nKoreksi ini hasil pemeriksaan langsung ke Cloudflare R2, bukan pembacaan kode.\n\n### Yang SEBENARNYA sudah jalan\n\n```\nbucket      zomet @ 0d2e...r2.cloudflarestorage.com (Cloudflare R2)\nobjek R2    342 · kredensial masih sah (listObjectsV2 berhasil diuji)\ndump lokal  /data/coolify/backups — 3,4 GB\nriwayat     570 sukses · 4 gagal\n```\n\n| Database | Jadwal | Ke R2 | Terakhir |\n|---|---|---|---|\n| ZPos `1fhosrzrapewqtv4wkqiw1rs` | `0 */3 * * *` | ✓ | 10 Nov 06:01 |\n| Z One `jznfq1n9zkfdqtjcjwbcnxwb` | `0 20 * * *` | ✓ | 9 Nov 20:00 |\n| ZX Gym `wko4doynkswavl3gqibxchge` | `0 20 * * *` | ✓ | 9 Nov 20:00 |\n\n### Yang MASIH BOLONG\n\n**Tidak punya jadwal backup sama sekali:**\n\n| Database | Dampak |\n|---|---|\n| **AcuMedis** `shlrypoiye8df6ijn99lnbii` | data pasien — paling serius |\n| **ZX Carwash** `9zrumir0odqrm3zoaxkh56wg` | transaksi, bon, antrian, kas harian |\n| **ZXRoom** `adyf5mac2kjppwuoqebk7naf` | properti & penyewaan |\n| **pajak-kb-api** `znoe26p9` | data wajib pajak |\n| MemberKit `e006bspftf2mjdmpbisks2k9` | member & tenant |\n| ytvault | kecil, tapi tanpa salinan |\n\n**Di luar Postgres — tidak ada mekanisme:**\n\n- Repo Gitea (bind mount `/root/gitea/data`) — **semua kode sumber**\n- Konfigurasi Coolify (`.env`, compose, volume `coolify-db`)\n- `.env` semua app (rahasia produksi; bocor = harus rotasi)\n- Berkas unduhan YTVault (besar, bisa diunduh ulang)\n\n**Temuan sampingan:** dari 334 objek ZPos di R2, ~320 bukan dump database —\nitu materi LLM Zadv yang tersimpan di jalur lama. Dump asli hanya ~14 terakhir.\n\n### Rencana perbaikan\n\nTidak perlu skrip baru maupun ubah kode. Mekanisme yang sama sudah terbukti\njalan untuk ZPos tiap 3 jam; yang kurang hanya mengisi jadwal di panel Coolify.\n\n| # | Database | Frekuensi | Ke S3 |\n|---|---|---|---|\n| 1 | ZX Carwash | `0 */3 * * *` (3 jam) | ✓ |\n| 2 | AcuMedis | `0 20 * * *` | ✓ |\n| 3 | ZXRoom | `0 20 * * *` | ✓ |\n| 4 | pajak-kb-api | `0 20 * * *` | ✓ |\n| 5 | MemberKit | `0 20 * * *` | ✓ |\n| 6 | ytvault | `0 20 * * *` | ✓ |\n\nSetelah keenam jadwal ini hidup, keenamnya mengikuti jalur yang sudah terbukti\n(570 sukses) — tidak ada komponen baru yang bisa gagal.\n\n**Tahap berikutnya** (belum dikerjakan, perlu keputusan terpisah):\n\n| # | Langkah | Alasan |\n|---|---|---|\n| 7 | `tar` harian repo Gitea → R2 | semua kode sumber ada di situ |\n| 8 | Backup `.env` terenkripsi → R2 | tanpa ini, DB saja tidak cukup untuk memulihkan app |\n| 9 | Uji restore satu DB ke container sementara | backup yang tak pernah diuji bukan backup |\n\n### Aturan masa depan untuk database baru\n\nSetiap kali app baru dibuat, **jadwal backupnya dibuat di hari yang sama.**\nDua kali sekarang DB baru lahir tanpa backup (ZX Carwash, AcuMedis). Lebih baik\nmenjadikannya bagian dari daftar pembuatan app daripada mengandalkan ingatan.\n\n### Status\n\nMenunggu perintah. Belum ada jadwal yang dibuat dan belum ada berkas yang\ndiubah.\n","media":"[]","urut":7,"createdAt":"2026-11-10T06:27:09.702Z","updatedAt":"2026-11-10T06:27:09.702Z"}],"children":[],"parent":null}